package org.springframework.aop.framework.autoproxy;
import java.util.List;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.framework.autoproxy.A17.Target1;
import org.springframework.aop.framework.autoproxy.A17.Target2;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;


/*****
 * 移动包的原因是想调用 AnnotationAwareAspectJAutoProxyCreator的 protected的方法，需要在同一个包下
 * @author Administrator
 *
 */
public class A17 {
    public static void main(String[] args) throws NoSuchMethodException {
    	test2();
    }
    
    
    /*
    第一个重要方法 findEligibleAdvisors 找到有【资格】的 Advisors
    a. 有【资格】的 Advisor 一部分是低级的, 可以由自己编写, 如下例中的 advisor3
    b. 有【资格】的 Advisor 另一部分是高级的, 由本章的主角解析 @Aspect 后获得
*/
	public static void test1() {
		GenericApplicationContext context = new GenericApplicationContext();
		context.registerBean("aspect1", Aspect1.class);
		context.registerBean("config", Config.class);
		context.registerBean(ConfigurationClassPostProcessor.class);// 加后处理器 解决@bean
		context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);// 解决切面的配置

		context.refresh();
		
		for (String name : context.getBeanDefinitionNames()) {
			//  System.out.println(name);
		};
		 
		AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
		List<Advisor> advisors = creator.findEligibleAdvisors(Target1.class, "target1");  //调用一个类 判断这个类有没有被切面包含
		for (Advisor advisor : advisors) {
			System.out.println(advisor);
		}
		 /******
		   org.springframework.aop.interceptor.ExposeInvocationInterceptor.ADVISOR 所有的切面都会用到的
           org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [AspectJExpressionPointcut: () execution(* foo())]; advice [org.springframework.aop.framework.autoproxy.A17$Config$1@7530ad9c]
                                 自 定义的基础切面 查询的类
           InstantiationModelAwarePointcutAdvisor: expression [execution(* foo())]; advice method [public void org.springframework.aop.framework.autoproxy.A17$Aspect1.before()]; perClauseKind=SINGLETON
                                高级切面的before通知对应的切面
           InstantiationModelAwarePointcutAdvisor: expression [execution(* foo())]; advice method [public void org.springframework.aop.framework.autoproxy.A17$Aspect1.after()]; perClauseKind=SINGLETON 
		          高级切面的after通知对应的切面
		  */
	}
	
	
	/*****
	  第二个重要方法 wrapIfNecessary
        a. 它内部调用 findEligibleAdvisors, 只要返回集合不空, 则表示需要创建代理
	 */
	public static void test2() {
		GenericApplicationContext context = new GenericApplicationContext();
		context.registerBean("aspect1", Aspect1.class);
		context.registerBean("config", Config.class);
		context.registerBean(ConfigurationClassPostProcessor.class);// 加后处理器 解决@bean
		context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);// 解决切面的配置

		context.refresh();

		for (String name : context.getBeanDefinitionNames()) {
			// System.out.println(name);
		}
		;

		AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
		Object o1 = creator.wrapIfNecessary(new Target1(), "target1", "target1");//第一个参数重要  第二三参数不重要 可以随意设置
		System.out.println(o1.getClass());
		Object o2 = creator.wrapIfNecessary(new Target2(), "target2", "target2");
		System.out.println(o2.getClass());

		((Target1) o1).foo();
	}
    
    
    
	  static class Target1 {
	        public void foo() {
	            System.out.println("target1 foo");
	        }
	    }

	    static class Target2 {
	        public void bar() {
	            System.out.println("target2 bar");
	        }
	    }
    
    
    /*** 
            * 定义一个高级切面类  定义两个通知
     * @author Administrator
     *
     */
    @Aspect
    static class Aspect1{
    	
    	@Before("execution(* foo())")
    	public void before() {
    	    System.out.println("aspect1  before....");
    	}
    	
    	@After("execution(* foo())")
    	public void after() {
    	    System.out.println("aspect1  after....");
    	}
    	
    }
    
    
    //定义一个初级类
    @Configuration
    static class Config {
    	
    	@Bean//创建切面类
    	public Advisor advisors(MethodInterceptor advice3) {
    		AspectJExpressionPointcut pointcut  =new AspectJExpressionPointcut();
    		pointcut.setExpression("execution(* foo())");
    		return new DefaultPointcutAdvisor(pointcut, advice3);//需要一个切点  一个通知
    		 
    	}
    	
    	
    	/***
    	 * 创建一个通知
    	 * @return
    	 */
    	@Bean
    	public MethodInterceptor advice3() {
    		return   new MethodInterceptor() {

				@Override
				public Object invoke(MethodInvocation invocation) throws Throwable {
					 System.out.println("advice3  before....");
					 Object result = invocation.proceed();
					 System.out.println("advice3  after....");
					return result;
					
					
				}
    			
    		};
    	}
    }

    
}